#!/usr/bin/python
"""
cre_lex_test.py: Tests for cre_lex.py
"""

from pprint import pprint
import re
import unittest

import cre_lex  # module under test


class LexerTest(unittest.TestCase):

  def testNoSpace(self):
    l = cre_lex.GetLexer()
    tokens = list(l.run('digits'))
    self.assertEqual(
        [('IDENTIFIER', 'digits', 0)],
        tokens)

  def testHexUnicode(self):
    l = cre_lex.GetLexer()

    tokens = list(l.run('0xFF'))
    self.assertEqual(u'\xff', tokens[0][1])

    tokens = list(l.run('&abcd'))
    self.assertEqual(u'\uabcd', tokens[0][1])

  def testChar(self):
    # All these things are valid in a character class.
    examples = [
        'wordchar',
        ':alnum',
        '::Greek',
        '&201b',
        '0x00',
        '&space',

        '!wordchar',
        '!:alnum',
        '!::Greek',

        '! wordchar',  # this space is valid

        'a-z',
        'abc-d',  # I prefer that this is written ab c-d

        'wordcha',  # TYPO.
        '!wordcha',  # TYPO
        ':alnu',  # TYPO
        '!:alnu',  # TYPO  -- these are not validated now.

        #'&spac',  # TYPO.  Not validated.
        #'&202',  # TYPO
        #'0x0',  # TYPO

        'any',   # some people might mistakenly do this.  oh well?
        'chars',   # some people might mistakenly do this.
        # or introduce clump as [any]

        # !chars['"]
        # !chars(wordchar ['"])

        # !chars(' ")
        # !chars(['"])

        'abc',  # a clump
        'a&b',  # a clump
        'a:b',  # a clump

        '0x00-z',  # mixed
        '0x00-&abcd',  # mixed
        ]
    for e in examples:
      l = cre_lex.GetLexer()
      tokens = l.run(e, start='class')
      print '--'
      print e
      pprint(list(tokens))

  def testSimple(self):
    examples = [
        'any',
        '!any',
        'digit+',
        # non-greedy.  TODO: should we tokenize ++ into a single operator?
        'digit++',
        'word*',
        'whitespace?',

        # Capture
        '{space}',
        '{digit as age}',
        'either A or B',
        'either "A" or "B"',
        'either (A B) or C',

        '%begin',
        '%end',

        ':alnum',
        '::Greek',  # unicode

        # Character classes.
        'chars[ab]',
        'chars[a b]',
        # valid range
        'chars[a-z]',

        # Not a range: a hyphen b
        'chars[a - z]',
        # invalid?  all chars separated by spaces
        'chars[a- z]',
        'chars[a -z]',
        '!chars[a-z]',
        'chars[a-z digit :alnum ::Greek]',
        r'chars[a-z hyphen space \n \1 \12 \123]',
        # !space isn't valid
        r'chars[!digit !:alnum !::Greek]',

        r'chars[\r \n]',

        'digit^3',
        'digit^(..3)',
        'backslash^(3..4)',
        'backslash^(N ..4)',
        'backslash^(N *)',
        'backslash^(P ?)',

        # hex digits
        '0x00 0xff 0xAf',

        '&abcd &0123',

        # TODO
        '%ASSERT(a) %ASSERTLEFT(b) !%ASSERT(a) !%ASSERTLEFT(b)',
        'REF(1)',

        'IF a THEN b ELSE c',

        # TODO: Can test strings here.  All the different escapes allowed.
        ]

    for e in examples:
      l = cre_lex.GetLexer()
      tokens = l.run(e)
      print '--'
      print e
      pprint(list(tokens))


class PegTest(unittest.TestCase):
  """This was testing the old parser PEGs.  Probably don't need it."""

  def testSimple(self):
    l = cre_lex.GetLexer()
    r = l.run('Foo = chars[0123a-zA-Z]')
    pprint(list(r))

  def testFull(argv):
    scanner = cre_lex.GetLexer()
    print scanner

    t = scanner.run('hi')
    print list(t)

    t = scanner.run(' hi bye ')
    print list(t)

    print '-'* 80

    t = scanner.run(' hi "str" hi ')
    print list(t)

    pos_table = []
    t = scanner.run(r' hi "str\nfoo\n" hi ', pos_table=pos_table)
    print list(t)
    print pos_table

    t = scanner.run(r' hi chars[ab] hi ', pos_table=pos_table)
    pprint(list(t))
    print pos_table

    t = scanner.run(r' hi chars[ab] chars[Xa-zA-Z] hi ', pos_table=pos_table)
    pprint(list(t))
    print pos_table


if __name__ == '__main__':
  unittest.main()
